/*
 * Copyright 2017 Huawei Technologies Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.openo.sdno.lcm.engine.impl.workflow;

import java.util.UUID;
import java.util.logging.Logger;

import org.openo.sdno.lcm.decomposer.BrsMapping;
import org.openo.sdno.lcm.engine.GenericWorkflowId;
import org.openo.sdno.lcm.exception.SouthboundExecutionException;
import org.openo.sdno.lcm.model.workplan.WorkPlan;
import org.openo.sdno.lcm.model.workplan.WorkPlanExecutionResult;
import org.openo.sdno.lcm.model.workplan.WorkPlanExecutionStrategy;
import org.openo.sdno.lcm.templatemodel.service.Instance;
import org.openo.sdno.lcm.templatemodel.service.Node;
import org.openo.sdno.lcm.util.Constants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * This workflow corresponds to the following state table row: "apiOperation":
 * "deploy", "currentState": "created", "newState": "deployed",
 * "transitionWorkflow": "deployCreated"
 */
@Component
public class GwfDeployCreated extends AtomicWorkflow {

    private static final String SDNO_NODE_NODE = "sdno.node.Node";

    private static final Logger log = Logger.getLogger("GwfDeployCreated");

    private BrsMapping brsMapping;

    /*
     * (non-Javadoc)
     * 
     * @see org.openo.sdno.lcm.engine.RegisterWorkflow#getWorkflowId()
     */
    @Override
    public String getWorkflowId() {

        return GenericWorkflowId.DEPLOYCREATED.toString();
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.openo.sdno.lcm.engine.impl.workflow.GenericWorkflowImpl#getNewState()
     */
    @Override
    protected String getNewState() {
        return Constants.LCM_LIFECYCLESTATE_DEPLOYED;
    }

    /*
     * (non-Javadoc)
     * 
     * @see org.openo.sdno.lcm.engine.impl.workflow.GenericWorkflowImpl#
     * updateTemplateInstance(org.openo.
     * sdno.lcm.templatemodel.service.Instance, java.lang.String)
     */
    @Override
    protected void updateTemplateInstancePreDispatch(Instance templateInstance) {
        // update the nodes with correct values for this workflow
        templateInstance.replacePropertyValueInAllNodes(Constants.LCM_ADMINSTATUS,
                Constants.LCM_ADMINISTRATIONSTATE_ACTIVE);
        templateInstance.replacePropertyValueInAllNodes(Constants.LCM_ACTIONSTATE, Constants.LCM_ACTIONSTATE_DEPLOYING);

        for (Node node : templateInstance.getNodes()) {

            // generate UUIDs for Nodes that will be created by atomic services
            if (node.isConnectionNode()) {
                String uuid = UUID.randomUUID().toString();
                node.setProperty("id", uuid, "string");
                log.info(String.format("Generated random ID property %s for Node %s", uuid, node.getId()));
            }
        }
    }

    @Override
    protected void updateTemplateInstancePostDispatch(Instance templateInstance) {

        templateInstance.replacePropertyValueInAllNodes(Constants.LCM_ACTIONSTATE, Constants.LCM_ACTIONSTATE_NORMAL);
    }

    /*
     * (non-Javadoc)
     * 
     * @see
     * org.openo.sdno.lcm.engine.impl.workflow.GenericWorkflowImpl#getLogger()
     */
    @Override
    protected Logger getLogger() {
        return log;
    }

    /**
     * Generate the Workplan via decomposer and execute it via dispatcher.
     * 
     * In the DeployCreated case we need to handle the file store writing AFTER
     * the decomposer so the IDs are all correct (some read from BRS etc)
     * 
     * @param csarId
     * @param apiOperation
     * @param templateInstance
     * @throws SouthboundExecutionException
     */
    protected void executeWorkplan(String csarId, String apiOperation, Instance templateInstance, String nsId)
            throws SouthboundExecutionException {

        // retrieve resources from BRS and fill required data
        this.fillResourceNodes(templateInstance);
        WorkPlan workPlan = this.decomposer.decompose(templateInstance, apiOperation, csarId);

        // need to store the instance after Node IDs have been generated by the
        // decomposer
        fileStoreHandler.storeInstanceToFile(templateInstance, nsId);

        WorkPlanExecutionResult dispatchResult = dispatcher.dispatch(workPlan, WorkPlanExecutionStrategy.FAIL_FAST);
        if (!dispatchResult.getOverallResult()) {
            throw new SouthboundExecutionException("Execution failed in the SBI:\n" + dispatchResult.toString());
        }
    }

    /**
     * 
     */
    public void fillResourceNodes(Instance instance) {

        for (Node node : instance.getNodes()) {

            if (node.getTypeName().equals(SDNO_NODE_NODE)) {
                log.info(String.format("fillResourceNodes: %s is a resource Node", node.getId()));

                try {
                    brsMapping.enrichResourceNode(node);
                } catch (Exception e) {
                    log.fine(e.toString());
                    log.warning(String.format(
                            "Failed to enrich the resource node %s with values from resource inventory due to %s",
                            node.getId(), e.getMessage()));
                }

            } else {
                log.fine(String.format("fillResourceNodes: %s is not a resource Node - no values will be filled",
                        node.getId()));
            }
        }
    }

    @Autowired
    public void setBrsMapping(BrsMapping brsMapping) {
        this.brsMapping = brsMapping;
    }

}
